package com.apes.autoparts.supplier.longsky;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.autoparts.supplier.platform.SupplierPlatformItem;
import com.apes.autoparts.supplier.platform.SupplierPlatformItemRepository;
import com.apes.autoparts.supplier.todo.SupplierPlatformTodoService;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.generator.service.SequenceService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.query.SqlService;
import com.apes.framework.util.CronExpression;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apestech.framework.json.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.swing.*;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

@Service("longSkyService")
public class LongSkyService<T, R>  extends LongSkyApi<T, R> {

    @Autowired
    private LongSkyRepository longSkyRepository;
    @Autowired
    private SupplierPlatformItemRepository supplierPlatformItemRepository;
    @Autowired
    private SupplierPlatformTodoService todoService;

    private final List<String> importantFields = Arrays.asList("NNO", "FA");

    @Autowired
    SequenceService sequenceService;


    /***
     * 处理长远数据
     */
    public void handHeap(SimpleRequest request) {
        JSONObject param = request.getJO();
        JSONArray jsonArray = param.getJSONArray("data");
        SupplierPlatformItem supplierPlatformItem = supplierPlatformItemRepository.findOne(param.getString("supplierPlatformItemId"));
        List<String> ids = jsonArray.stream().map(v -> {
            JSONObject json = (JSONObject) v;
            return String.valueOf(Math.abs(json.getIntValue("ID")));
        }).collect(Collectors.toList());

        // 获取缓存表的配件id
        Map map = new HashMap();
        if (ids != null && ids.size() != 0)
            longSkyRepository.findByIdsAndSupplierPlatformItem(ids, supplierPlatformItem.getId()).forEach(map1 -> {
                map.put(map1.get("CYID"), new JSONObject(map1));
            });
        // 获取属于新建的数据
        JSONArray newLongSky = jsonArray.stream().filter(v -> {
            JSONObject json = (JSONObject) v;
            if (map.get(String.valueOf(Math.abs(json.getIntValue("ID")))) == null)
                return true;
            return false;
        }).collect(Collectors.toCollection(JSONArray::new));
        // 获取属于更新的数据
        JSONArray updateLongSky = jsonArray.stream().filter(v -> {
            JSONObject json = (JSONObject) v;
            if (map.get(String.valueOf(Math.abs(json.getIntValue("ID")))) != null)
                return true;
            return false;
        }).collect(Collectors.toCollection(JSONArray::new));
        saveUpdateData(updateLongSky, supplierPlatformItem, map);
        saveCreateData(newLongSky, supplierPlatformItem);
        if(request.getJO().get("lastData") != null &&
                request.getJO().getBooleanValue("lastData") &&
                "synTotal".equals(request.getJO().getString("action")))
            deleteData(supplierPlatformItem);
    }

    @OutboxSubscriber(name = "长远：删除", eventType = "D")
    private void deleteData(SupplierPlatformItem supplierPlatformItem) {
        List condition = new ArrayList();
        condition.add(MapUtil.mapper("field","id", "operator", "EQ", "value", "auto.supplierPlatform.synTotalTaskLongSky"));
        List list = ((Page<Object>)SpringManager.getBean(DomainService.class).invoke("schedule.task.findAll",
                MapUtil.mapper("condition", condition, "size", 20, "page", 0))).getContent();
        if (list == null || list.size()==0) return;
        Map task = MapUtil.mapped(list.get(0));
        List<Map> cronExpression = longSkyRepository.findBySupplierPlatformItemAndNotUpdate(supplierPlatformItem.getId(), getHour(task.get("cronExpression").toString()) * 2);
        List<Map> newList= new ArrayList<>();
        for (Map map : cronExpression) {
            Map newMap = new HashMap(map);
            newMap.put("ID", newMap.get("CYID"));
            newList.add(newMap);
        }
        try {
            todos(JSONArray.parseArray(JSON.toJSONString(newList)), supplierPlatformItem, "delete", new HashMap());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        longSkyRepository.deleteBySupplierPlatformItemAndNotUpdate(supplierPlatformItem.getId(),
                getHour(task.get("cronExpression").toString()) * 2);
    }


    /***
     * 保存数据(可能存在废弃的情况，编码为负数，内部转化为有效标记)
     */
    private LongSky saveAndFlush(JSONObject param, SupplierPlatformItem supplierPlatformItem) {
        LongSky longSky = longSkyRepository.findOne(JpaDsl.toCriteriaByEq(
                "supplierPlatformItem.id", supplierPlatformItem.getId(),
                "CYID", Math.abs(param.getIntValue("ID"))
        )).orElse(null);

//        if (checkLongSkyData(longSky, param))
        pushTodo(longSky, param, supplierPlatformItem); //推送待办数据
//        else return null;
        if (longSky == null) {
            longSky = new LongSky();
            longSky.setCYID(String.valueOf(Math.abs(param.getIntValue("ID")))); // 对于编码取绝对值
        }

        if (param.getIntValue("ID") < 0) longSky.setValid(false); // 当值为负数时，当前值为无效数据

        longSky.setSupplierPlatformItem(supplierPlatformItem);
        longSky.setCP(param.getString("CP"));
        longSky.setNNO(param.getString("NNO"));
        longSky.setNA1(param.getString("NA1"));
        longSky.setKCAMOUNT(param.getDoubleValue("KCAMOUNT"));
        longSky.setOPRC(param.getDoubleValue("OPRC"));
        longSky.setFA(param.getString("FA"));
        longSky.setTY(param.getString("TY"));
        longSky.setPOSI(param.getString("POSI"));
        longSky.setDEPOTNO(param.getString("DEPOTNO"));
        longSky.setDC(param.getString("DC"));
        longSky.setUNIT(param.getString("UNIT"));
        longSky.setNOTE(param.getString("NOTE"));
        return longSkyRepository.saveAndFlush(longSky);
    }

    /***
     * 推送待办
     */
    public void pushTodo(LongSky longSky,JSONObject param, SupplierPlatformItem supplierPlatformItem) {
        JSONObject todoJson = new JSONObject();

        if (longSky == null) {
            longSky = new LongSky();
            todoJson.put("createFlag", true);
        }
        if (param.getIntValue("ID") < 0) todoJson.put("deleteFlag", true);

        Map m = MapUtil.mapper(
                "source", String.valueOf(Math.abs(param.getIntValue("ID"))),
                "supplierPlatformItem", MapUtil.mapper(
                        "id", supplierPlatformItem.getId()
                ),
                "oldBrandName", "",
                "brandName", "",
                "oldOriginPlace", longSky.getFA(),
                "originPlace", param.getString("FA"),
                "oldPartCode", longSky.getNNO(),
                "partCode", param.getString("NNO"),
                "oldPartCodeName", longSky.getNA1(),
                "partCodeName",  param.getString("NA1"),
                "oldUnit", longSky.getUNIT(),
                "unit", param.getString("UNIT"),
                "stockQty", param.getDoubleValue("KCAMOUNT"),
                "untaxPrice", param.getDoubleValue("OPRC"),
                "batch", param.getString("batch")
        );

        todoJson.putAll(m);

        SimpleRequest request = new SimpleRequest();
        request.setData(todoJson);
        todoService.insert(request);
    }

    @Override
    public List<Map> getRowData(SupplierPlatformItem supplierPlatformItem, String source) {

        return longSkyRepository.getRowData(source);
    }


    @Override
    public void handleRow(SimpleRequest request) {

    }


    /**
     * 保存属于创建的数据,并推送待办
     * @param jsonArray
     * @param supplierPlatformItem
     */
    private void saveCreateData(JSONArray jsonArray, SupplierPlatformItem supplierPlatformItem) {
        for (Object o : jsonArray) {
            JSONObject json = (JSONObject) o;
            json.put("CYID", json.getString("ID"));
        }
        List<LongSky> longSkies = JSONArray.parseArray(jsonArray.toString(), LongSky.class);
        for (LongSky longSky : longSkies) {
            longSky.setSupplierPlatformItem(supplierPlatformItem);
            longSky.setId(null);
        }

        todos(jsonArray, supplierPlatformItem,"create" , new HashMap<>());
        longSkyRepository.saveAll(longSkies);
    }

    /***
     * 保存属于更新的数据和推送待办
     * @param updateLongSky
     * @param supplierPlatformItem
     * @param oldLongSky
     */
    private void saveUpdateData(JSONArray updateLongSky, SupplierPlatformItem supplierPlatformItem, Map oldLongSky) {
        List<LongSky> longSkies = new ArrayList<>();
        JSONArray importantAttribute = new JSONArray();
        JSONArray update = new JSONArray();
        JSONArray delete = new JSONArray();
        for (Object o : updateLongSky) {
            JSONObject json = (JSONObject) o;
            // ID为负是删除
            if (json.getIntValue("ID") < 0)  delete.add(json);
             // 重要属性发生改变
            else if (checkImportantUpdate(json, (JSONObject) oldLongSky.get(String.valueOf(Math.abs(json.getIntValue("ID"))))))
                importantAttribute.add(json);
            else update.add(json);
            LongSky longSky = longSkyRepository.findOne(((JSONObject) oldLongSky.get(String.valueOf(Math.abs(json.getIntValue("ID"))))).getString("ID"));
            jsonToLongSky(json, longSky);
            longSkies.add(longSky);
        }
        todos(importantAttribute, supplierPlatformItem,"importUpdate", oldLongSky);
        todos(update, supplierPlatformItem,"update", oldLongSky);
        todos(delete, supplierPlatformItem,"delete", oldLongSky);

        longSkyRepository.saveAll(longSkies);
    }

    private void todos(JSONArray newLongSkies, SupplierPlatformItem supplierPlatformItem, String property, Map oldLongSkies) {
        if (newLongSkies.size() == 0 ) return;
        JSONObject param = new JSONObject();
        param.put("property", property);
        param.put("supplierPlatformItemId", supplierPlatformItem.getId());

        List<JSONObject> collect = newLongSkies.stream().map(o -> {
            JSONObject newLongSky = (JSONObject) o;
            JSONObject oldLongSky = (JSONObject) oldLongSkies.get(newLongSky.getString("ID"));
            JSONObject todo =  new JSONObject();
            JSONObject supplierItem = new JSONObject();
            supplierItem.put("id", supplierPlatformItem.getId());
            todo.put("source", String.valueOf(Math.abs(newLongSky.getIntValue("ID"))));
            todo.put("supplierPlatformItem", supplierItem);
            todo.put("oldBrandName","");
            todo.put("brandName", "");
            todo.put("oldOriginPlace",oldLongSky != null ? oldLongSky.getString("FA") :"");
            todo.put("originPlace", newLongSky.getString("FA"));
            todo.put("oldPartCode", oldLongSky != null ? oldLongSky.getString("NNO") : "");
            todo.put("partCode", newLongSky.getString("NNO"));
            todo.put("oldPartCodeName", oldLongSky != null ? oldLongSky.getString("NA1") : "");
            todo.put("partCodeName", newLongSky.getString("NA1"));
            todo.put("oldUnit", oldLongSky != null ? oldLongSky.getString("UNIT") : "");
            todo.put("unit", newLongSky.getString("UNIT"));
            todo.put("stockQty", newLongSky.getDoubleValue("KCAMOUNT"));
            todo.put("untaxPrice", newLongSky.getDoubleValue("OPRC"));
            todo.put("batch", DateUtil.format(new Date(), DateUtil.SHOW_DATE_NUMBER_FORMAT));
            return todo;
        }).collect(Collectors.toList());
        param.put("data", collect);
        SimpleRequest request = new SimpleRequest();
        request.setData(param);
        todoService.inserts(request);
    }

    private void jsonToLongSky(JSONObject json, LongSky longSky) {
        longSky.setCP(json.getString("CP"));
        longSky.setDC(json.getString("DC"));
        longSky.setDEPOTNO(json.getString("DEPOTNO"));
        longSky.setFA(json.getString("FA"));
        longSky.setKCAMOUNT(json.get("KCAMOUNT") != null ? json.getDoubleValue("KCAMOUNT") : 0);
        longSky.setNA1(json.getString("NA1"));
        longSky.setNNO(json.getString("NNO"));
        longSky.setNOTE(json.getString("NOTE"));
        longSky.setOPRC(json.get("OPRC") != null ? json.getDoubleValue("OPRC") : 0);
        longSky.setPOSI(json.getString("POSI"));
        longSky.setTY(json.getString("TY"));
        longSky.setUNIT(json.getString("UNIT"));
    }

    /***
     * 判断是否重要属性被修改
     */
    private boolean checkImportantUpdate(JSONObject newData, JSONObject oldData) {
        return importantFields.stream().anyMatch(field -> {
            return !checkEqual(newData.getString(field), oldData.getString(field.toUpperCase()));
        });
    }

    /***
     * 用于比较两个字符串是否相等
     */
    private boolean checkEqual(String str, String str1) {
        if (StringUtils.isEmpty(str) && StringUtils.isEmpty(str1)) return true;
        if (str == null || str1 == null) return false;
        return str.equals(str1);
    }

    public void debugging(SimpleRequest request) {
        JSONArray data = request.getJO().getJSONArray("data");
        List<LongSkyDebug> list = JSONArray.parseArray(data.toString(), LongSkyDebug.class);
        String supplierPlatformItemId = request.getJO().getString("supplierPlatformItemId");
        SupplierPlatformItem supplierPlatformItem = supplierPlatformItemRepository.findOne(supplierPlatformItemId);
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setSupplierPlatformItem(supplierPlatformItem);
            list.get(i).setCYID(data.getJSONObject(i).getString("ID"));
            list.get(i).setId(sequenceService.getId(LongSkyDebug.CONST_TABLE_NAME));
        }
        SpringManager.getBean(LongSkyDebugRepository.class).save(list);
    }


    private long getHour(String cron){
        CronExpression exp;
        try {
            exp = new CronExpression(cron);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        Date startDate = exp.getNextValidTimeAfter(new Date());
        Date endDate = exp.getNextValidTimeAfter(startDate);
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long diff = endDate.getTime() - startDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = ( diff % nd / nh ) + ( day * 24 );
        return hour;
    }
}
